package com.java.code.socket;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("channelRead: read server back");
        ByteBuf buf = (ByteBuf) msg;
        byte[] res = new byte[buf.readableBytes()];
        buf.readBytes(res);
        System.out.println("server message:" + new String(res));
        // 引用计数减1，到达零的时候，回收空间
        buf.release();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 当出现异常时就关闭连接
        cause.printStackTrace();
        ctx.close();
    }


    // 连接成功后，向server发送消息
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String msg = "connect to server!";
        ByteBuf message = ctx.alloc().buffer(4 * msg.length());
        message.writeBytes(msg.getBytes());
        // 这里是演示一下 粘包 和拆包的问题
        // 1.粘包 缓存区没有满 将缓存区放满再发送出去 叫粘包
        // 2.拆包 缓存区满了 将数据拆分成多个部分再发送出去 叫拆包
        for(int i=0;i<1000;i++){
            ctx.channel().writeAndFlush(
                    Unpooled.copiedBuffer("hello world 世界你好,Netty技术学习".getBytes())
            );
        }
        //那么如何解决呢
        //1. 固定长度的拆包器 FixedLengthFrameDecoder
        //每个数据包的长度都是固定的，比如 1024，那么只需要把这个拆包器加到 pipeline 中，Netty 会把一个个长度为 1024 的数据包 (ByteBuf) 传递到下一个 channelHandler。
        //2. 行拆包器 LineBasedFrameDecoder
        //它是一个特殊的分隔符拆包器，以换行符作为结束符。
        //3. 分隔符拆包器 DelimiterBasedFrameDecoder
        //可以自定义自己的分隔符。
        //4. 基于长度域拆包器 LengthFieldBasedFrameDecoder

        ctx.write(message);
        // ctx.write(Object)方法不会使消息写入到通道上，他被缓冲在了内部，需要调用ctx.flush()把缓冲区中数据强行输出。
        // 或者用更简洁的cxt.writeAndFlush(msg)
        ctx.flush();
    }
}
